


// 一、将下面异步代码使用 Promise 的方式改进
function promiseTime(time, fn) {
    return new Promise((resolve) => {
        setTimeout(() => resolve(fn()), time);
    });
}
const timeA = () => promiseTime(10, () => {
    var a = 'hello'
    return a;
});
const timeB = () => promiseTime(10, () => {
    var b = 'lagou'
    return b;
});
const timeC = () => promiseTime(10, () => {
    var c = 'I ❤️ U'
    return c;
});

const timeFn = async () => {
    const a = await timeA();
    const b = await timeB();
    const c = await timeC();
    console.log(a + b + c);
}
timeFn();




console.log('// 二、基于以下代码完成下面的四个练习');
const fp = require('lodash/fp')
// 数据：horsepower 马力，dollar_value 价格，in_stock 库存
const cars = [{
        name: 'Ferrari FF',
        horsepower: 660,
        dollar_value: 700000,
        in_stock: true
    },
    {
        name: 'Spyker C12 Zagato',
        horsepower: 650,
        dollar_value: 648000,
        in_stock: false
    },
    {
        name: 'Jaguar XKR-S',
        horsepower: 550,
        dollar_value: 132000,
        in_stock: false
    },
    {
        name: 'Audi R8',
        horsepower: 525,
        dollar_value: 114200,
        in_stock: false
    },
    {
        name: 'Aston Martin One-77',
        horsepower: 750,
        dollar_value: 185000,
        in_stock: true
    },
    {
        name: 'Pagani Huayra',
        horsepower: 700,
        dollar_value: 130000,
        in_stock: false
    }
]


console.log('// 练习1：使用组合函数 fp.flowRight() 重新实现下面这个函数');
// let isLastInStock = function(cars){
//     // 获取最后一条数据
//     let last_car = fp.last(cars)
//     // 获取最后一条数据的 in_stock 属性值
//     return fp.prop('in_stock', last_car)
// }

const isLastInStock = fp.flowRight(fp.prop('in_stock'), fp.last);
const lastInStock = isLastInStock(cars)
console.log('lastInStock:', lastInStock);


console.log('练习2：使用 fp.flowRight()、fp.prop() 和 fp.first() 获取第一个 car 的 name');
const firstCarName = fp.flowRight(fp.prop('name'), fp.first);
const name = firstCarName(cars)
console.log('name:', name);


console.log('练习3：使用帮助函数 _average 重构 averageDollarValue，使用函数组合的方式实现');
let _average = function (xs) {
    return fp.reduce(fp.add, 0, xs) / xs.length
}

const averageDollarValueFn = fp.flowRight(_average, fp.map(fp.prop('dollar_value')));
const averageDollarValue = averageDollarValueFn(cars)
console.log('averageDollarValue:', averageDollarValue);


console.log('练习4：使用 flowRight 写一个 sanitizeNames() 函数，返回一个下划线连续的小写字符串， 把数组中的 name 转换为这种形式，例如：sanitizeNames(["Hello World"]) => ["hello_world"]');
let _underscore = fp.replace(/\W+/g, '_') // 无须改动，并在 sanitizeNames 中使用它

function sanitizeNames(v) {
    return fp.flowRight(_underscore, fp.toLower, fp.props('name'))(v);
}

const names = fp.map(sanitizeNames, cars);
cars.map((val, index) => val['name'] = names[index]);
console.log('sanitizeNames:', cars);





console.log('三、基于下面提供的代码，完成后续的四个练习')
// const fp = require('lodash/fp')
const {
    Maybe,
    Container
} = require('./support')
console.log('练习1：使用 fp.add(x, y) 和 fp.map(f,x) 创建一个能让 functor 里的值增加的函数 ex1');
let maybe = Maybe.of([5, 6, 1])

let ex1 = (v) => {
    // 你需要实现的函数。。。
    let num = 0;
    fp.map(val => num = fp.add(num, val), v);
    return num;
}
const r = maybe.map(ex1)._value;
console.log(r);


console.log('练习2：实现一个函数 ex2，能够使用 fp.first 获取列表的第一个元素');
let xs = Container.of(['do', 'ray', 'me', 'fa', 'so', 'la', 'ti', 'do'])
let ex2 = (array) => {
    const maybe = Maybe.of(array).map(fp.first);
    // // 你需要实现的函数。。。
    return maybe._value;
}
xs = xs.map(ex2);
console.log(xs._value);


console.log('练习3：实现一个函数 ex3，使用 safeProp 和 fp.first 找到 user 的名字的首字母');
let safeProp = fp.curry(function (x, o) {
    return Maybe.of(o[x])
})
let user = {
    id: 2,
    name: 'Albert'
}

let ex3 = (obj) => {
    const res = safeProp('name', obj).map((obj) => fp.first(obj));
    return res._value;
}
const res3 = ex3(user);
console.log(res3);


console.log('练习4：使用 Maybe 重写 ex4，不要有 if 语句');
let ex4 = function (n) {
    const maybe = Maybe.of(n).map(n => parseInt(n));
    return maybe._value;
}
console.log(ex4('123'), ex4(null));







// -----------------------------------------------------------------------------------------------
// console.log('四、手写实现 MyPromise 源码')
// console.log('见myPromise.js文件\n');

const { reject, values } = require('lodash');
const MyPromise = require('./mypromise');
/* 
1. 基本实现
2、Promise执行过程中，resolve、reject 是异步
3、then方法的多次调用
4、then方法的链式调用
5、then方法返回promise对象
6、then方法识别返回的是自身，容错处理
7、错误处理
8、then方法编程可选参数
*/
const myPromise = new MyPromise((resolve,reject)=>{

    resolve('成功了');
    // reject(new Error('失败'));

    // 异步2、Promise执行过程中，resolve、reject 是异步
    // setTimeout(() => {
    //     resolve('成功了');
    //     reject('失败');

    // }, 1000);

// 4、then方法的链式调用
})
// .then(value=>{
//     console.log(value);
//     return 100;
// },(err)=>{
//     console.log(err);

// }).then(value=>{
//     console.log(value);

//     return 200;
// },(err)=>{
//     console.log(err);

// });

// // 3、then方法的多次调用
// // 5、then方法返回promise对象
// myPromise.then((value)=>{
//     console.log(value);
//     return new MyPromise((resolve,reject)=>{
//         resolve(300);
//     });
// },(err)=>{
//     console.log(err);

// }).then((values)=>{
//     console.log('return promise',values);
// },((err)=>{
//     console.log('return promise error',err);

// }));

// 6、then方法识别返回的是自身，容错处理
// 

// const myPromise = new MyPromise((resolve,reject)=>{
   
//     // resolve('成功了');
//     // throw Error('手动抛出');

//     // setTimeout(() => {
//         // throw Error('手动抛出');
//         // resolve('成功了');
//         reject('reject');

//     // }, 10);

// });
// const p2 = myPromise.then(value=>{
//     console.log('最后一个',value);
//     throw Error('我是错误');
//     return 1000;
// },(err)=>{
//     console.log('err:::',err);
//     return 500;

// }).then(value=>{
//     console.log('value2:::',value);
    
// },(err)=>{
//     console.log('err2:::',err);

// })

// then方法编程可选参数
// myPromise.then().then().then((value)=>{
//     console.log('mypromise:',value);
// })

// const promise3 = new MyPromise((resolve,reject)=>{
//     resolve('成功2');
// }).then((values)=>{
//     console.log(values);
//     return 'promise3 change'
// });

// all
// Promise.all(['res',myPromise,promise3]).then(value=>{
//     console.log('all:',value);
// })

// resolve
// const promise4 = new MyPromise((resolve,reject)=>{});
// promise4.resolve('4');
// promise4.then(value=>{
//     console.log('promise4:',value);
// });

function p5() {
    return new MyPromise(function(resolve,reject){
        // resolve('111');
        reject('my error')
    });
}


p5().finally(()=>{
    console.log('finally')
}).then(value=>{
    console.log(value);
},err=>{
    console.log(err);
}).catch((e)=>{
    console.log(e);
});